/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */
package xowl.interpreter.frontends.functional;

import java.io.IOException;
import java.io.Writer;
import java.util.List;
import xowl.lang.actions.FunctionDefinition;
import xowl.lang.owl2.Annotation;
import xowl.lang.owl2.AnnotationAssertion;
import xowl.lang.owl2.AnnotationPropertyDomain;
import xowl.lang.owl2.AnnotationPropertyRange;
import xowl.lang.owl2.AsymmetricObjectProperty;
import xowl.lang.owl2.Axiom;
import xowl.lang.owl2.ClassAssertion;
import xowl.lang.owl2.ClassExpression;
import xowl.lang.owl2.DataPropertyAssertion;
import xowl.lang.owl2.DataPropertyDomain;
import xowl.lang.owl2.DataPropertyExpression;
import xowl.lang.owl2.DataPropertyRange;
import xowl.lang.owl2.DatatypeDefinition;
import xowl.lang.owl2.Declaration;
import xowl.lang.owl2.DifferentIndividuals;
import xowl.lang.owl2.DisjointClasses;
import xowl.lang.owl2.DisjointDataProperties;
import xowl.lang.owl2.DisjointObjectProperties;
import xowl.lang.owl2.DisjointUnion;
import xowl.lang.owl2.EquivalentClasses;
import xowl.lang.owl2.EquivalentDataProperties;
import xowl.lang.owl2.EquivalentObjectProperties;
import xowl.lang.owl2.FunctionalDataProperty;
import xowl.lang.owl2.FunctionalObjectProperty;
import xowl.lang.owl2.HasKey;
import xowl.lang.owl2.IndividualExpression;
import xowl.lang.owl2.InverseFunctionalObjectProperty;
import xowl.lang.owl2.InverseObjectProperties;
import xowl.lang.owl2.IrreflexiveObjectProperty;
import xowl.lang.owl2.NegativeDataPropertyAssertion;
import xowl.lang.owl2.NegativeObjectPropertyAssertion;
import xowl.lang.owl2.ObjectPropertyAssertion;
import xowl.lang.owl2.ObjectPropertyDomain;
import xowl.lang.owl2.ObjectPropertyExpression;
import xowl.lang.owl2.ObjectPropertyRange;
import xowl.lang.owl2.ReflexiveObjectProperty;
import xowl.lang.owl2.SameIndividual;
import xowl.lang.owl2.SubAnnotationPropertyOf;
import xowl.lang.owl2.SubClassOf;
import xowl.lang.owl2.SubDataPropertyOf;
import xowl.lang.owl2.SubObjectPropertyOf;
import xowl.lang.owl2.SymmetricObjectProperty;
import xowl.lang.owl2.TransitiveObjectProperty;

/**
 *
 * @author Laurent WOUTERS
 */
public class AxiomWriter extends xowl.interpreter.frontends.AbstractAxiomWriter {
    private ExpressionWriter expWriter;
    
    public AxiomWriter(FunctionalWriter parent) {
        expWriter = new ExpressionWriter(parent);
    }
    
    public void writeAnnotation(Writer writer, Annotation annotation) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.ontoAnnotation);
        writer.write("(");
        for (Annotation annot : annotation.getAllAnnotations())
            writeAnnotation(writer, annot);
        expWriter.writeEntity(writer, annotation.getAnnotProperty());
        if (annotation.getAnnotValue() instanceof xowl.lang.owl2.IRI)
            expWriter.writeEntity(writer, (xowl.lang.owl2.IRI)annotation.getAnnotValue());
        else if (annotation.getAnnotValue() instanceof xowl.lang.owl2.AnonymousIndividual)
            expWriter.writeAnonymousIndividual(writer, (xowl.lang.owl2.AnonymousIndividual)annotation.getAnnotValue());
        else
            expWriter.writeLiteral(writer, (xowl.lang.owl2.Literal)annotation.getAnnotValue());
        writer.write(")");
    }

    protected void writeAnnotations(Writer writer, Axiom axiom) throws IOException {
        for (Annotation annotation : axiom.getAllAnnotations())
            writeAnnotation(writer, annotation);
    }
    
    @Override protected void writeDeclaration(Writer writer, Declaration axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.ontoAnnotation);
        writer.write("(");
        writeAnnotations(writer, axiom);
        writer.write(axiom.getType());
        writer.write("(");
        expWriter.writeEntity(writer, axiom.getEntity());
        writer.write(")");
        writer.write(")");
    }

    @Override protected void writeDatatypeDefinition(Writer writer, DatatypeDefinition axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomDatatypeDefinition);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeDatatype(writer, axiom.getDatatype());
        writer.write(" ");
        expWriter.writeDatatype(writer, axiom.getDatarange());
        writer.write(")");
    }

    @Override protected void writeSubClassOf(Writer writer, SubClassOf axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomSubClassOf);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeClass(writer, axiom.getClasse());
        writer.write(" ");
        expWriter.writeClass(writer, axiom.getSuperClass());
        writer.write(")");
    }

    @Override protected void writeEquivalentClasses(Writer writer, EquivalentClasses axiom) throws IOException {
        List<ClassExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getClassSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomSubClassOf);
        writer.write("(");
        writeAnnotations(writer, axiom);
        boolean first = true;
        for (ClassExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeClass(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeDisjointClasses(Writer writer, DisjointClasses axiom) throws IOException {
        List<ClassExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getClassSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomSubClassOf);
        writer.write("(");
        writeAnnotations(writer, axiom);
        boolean first = true;
        for (ClassExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeClass(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeDisjointUnion(Writer writer, DisjointUnion axiom) throws IOException {
        List<ClassExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getClassSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomSubClassOf);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeClass(writer, axiom.getClasse());
        boolean first = true;
        for (ClassExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeClass(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeSubObjectPropertyOf(Writer writer, SubObjectPropertyOf axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomSubObjectPropertyOf);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(" ");
        expWriter.writeObjProp(writer, axiom.getSuperObjectProperty());
        writer.write(")");
    }

    @Override protected void writeEquivalentObjectProperties(Writer writer, EquivalentObjectProperties axiom) throws IOException {
        List<ObjectPropertyExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getObjectPropertySeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomEquivalentObjectProperties);
        writer.write("(");
        writeAnnotations(writer, axiom);
        boolean first = true;
        for (ObjectPropertyExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeObjProp(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeDisjointObjectProperties(Writer writer, DisjointObjectProperties axiom) throws IOException {
        List<ObjectPropertyExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getObjectPropertySeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomDisjointObjectProperties);
        writer.write("(");
        writeAnnotations(writer, axiom);
        boolean first = true;
        for (ObjectPropertyExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeObjProp(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeInverseObjectProperties(Writer writer, InverseObjectProperties axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomInverseObjectProperties);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(" ");
        expWriter.writeObjProp(writer, axiom.getInverse());
        writer.write(")");
    }

    @Override protected void writeObjectPropertyDomain(Writer writer, ObjectPropertyDomain axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomObjectPropertyDomain);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(" ");
        expWriter.writeClass(writer, axiom.getClasse());
        writer.write(")");
    }

    @Override protected void writeObjectPropertyRange(Writer writer, ObjectPropertyRange axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomObjectPropertyRange);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(" ");
        expWriter.writeClass(writer, axiom.getClasse());
        writer.write(")");
    }

    @Override protected void writeFunctionalObjectProperty(Writer writer, FunctionalObjectProperty axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomFunctionalObjectProperty);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(")");
    }

    @Override protected void writeInverseFunctionalObjectProperty(Writer writer, InverseFunctionalObjectProperty axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomInverseFunctionalObjectProperty);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(")");
    }

    @Override protected void writeReflexiveObjectProperty(Writer writer, ReflexiveObjectProperty axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomReflexiveObjectProperty);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(")");
    }

    @Override protected void writeIrreflexiveObjectProperty(Writer writer, IrreflexiveObjectProperty axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomIrreflexiveObjectProperty);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(")");
    }

    @Override protected void writeSymmetricObjectProperty(Writer writer, SymmetricObjectProperty axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomSymmetricObjectProperty);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(")");
    }

    @Override protected void writeAsymmetricObjectProperty(Writer writer, AsymmetricObjectProperty axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomAsymmetricObjectProperty);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(")");
    }

    @Override protected void writeTransitiveObjectProperty(Writer writer, TransitiveObjectProperty axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomTransitiveObjectProperty);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(")");
    }

    @Override protected void writeSubDataPropertyOf(Writer writer, SubDataPropertyOf axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomSubDataPropertyOf);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeDataProp(writer, axiom.getDataProperty());
        writer.write(" ");
        expWriter.writeDataProp(writer, axiom.getSuperDataProperty());
        writer.write(")");
    }

    @Override protected void writeEquivalentDataProperties(Writer writer, EquivalentDataProperties axiom) throws IOException {
        List<DataPropertyExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getDataPropertySeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomEquivalentDataProperties);
        writer.write("(");
        writeAnnotations(writer, axiom);
        boolean first = true;
        for (DataPropertyExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeDataProp(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeDisjointDataProperties(Writer writer, DisjointDataProperties axiom) throws IOException {
        List<DataPropertyExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getDataPropertySeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomDisjointDataProperties);
        writer.write("(");
        writeAnnotations(writer, axiom);
        boolean first = true;
        for (DataPropertyExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeDataProp(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeDataPropertyDomain(Writer writer, DataPropertyDomain axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomDataPropertyDomain);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeDataProp(writer, axiom.getDataProperty());
        writer.write(" ");
        expWriter.writeClass(writer, axiom.getClasse());
        writer.write(")");
    }

    @Override protected void writeDataPropertyRange(Writer writer, DataPropertyRange axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomDataPropertyRange);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeDataProp(writer, axiom.getDataProperty());
        writer.write(" ");
        expWriter.writeDatatype(writer, axiom.getDatarange());
        writer.write(")");
    }

    @Override protected void writeFunctionalDataProperty(Writer writer, FunctionalDataProperty axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomFunctionalDataProperty);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeDataProp(writer, axiom.getDataProperty());
        writer.write(")");
    }

    @Override protected void writeSameIndividual(Writer writer, SameIndividual axiom) throws IOException {
        List<IndividualExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getIndividualSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomSameIndividual);
        writer.write("(");
        writeAnnotations(writer, axiom);
        boolean first = true;
        for (IndividualExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeIndividual(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeDifferentIndividuals(Writer writer, DifferentIndividuals axiom) throws IOException {
        List<IndividualExpression> list = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getIndividualSeq());
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomDifferentIndividuals);
        writer.write("(");
        writeAnnotations(writer, axiom);
        boolean first = true;
        for (IndividualExpression exp : list) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeIndividual(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeClassAssertion(Writer writer, ClassAssertion axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomClassAssertion);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeClass(writer, axiom.getClasse());
        writer.write(" ");
        expWriter.writeIndividual(writer, axiom.getIndividual());
        writer.write(")");
    }

    @Override protected void writeObjectPropertyAssertion(Writer writer, ObjectPropertyAssertion axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomObjectPropertyAssertion);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(" ");
        expWriter.writeIndividual(writer, axiom.getIndividual());
        writer.write(" ");
        expWriter.writeIndividual(writer, axiom.getValueIndividual());
        writer.write(")");
    }

    @Override protected void writeNegativeObjectPropertyAssertion(Writer writer, NegativeObjectPropertyAssertion axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomNegativeObjectPropertyAssertion);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeObjProp(writer, axiom.getObjectProperty());
        writer.write(" ");
        expWriter.writeIndividual(writer, axiom.getIndividual());
        writer.write(" ");
        expWriter.writeIndividual(writer, axiom.getValueIndividual());
        writer.write(")");
    }

    @Override protected void writeDataPropertyAssertion(Writer writer, DataPropertyAssertion axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomDataPropertyAssertion);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeDataProp(writer, axiom.getDataProperty());
        writer.write(" ");
        expWriter.writeIndividual(writer, axiom.getIndividual());
        writer.write(" ");
        expWriter.writeLiteral(writer, axiom.getValueLiteral());
        writer.write(")");
    }

    @Override protected void writeNegativeDataPropertyAssertion(Writer writer, NegativeDataPropertyAssertion axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomNegativeDataPropertyAssertion);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeDataProp(writer, axiom.getDataProperty());
        writer.write(" ");
        expWriter.writeIndividual(writer, axiom.getIndividual());
        writer.write(" ");
        expWriter.writeLiteral(writer, axiom.getValueLiteral());
        writer.write(")");
    }

    @Override protected void writeHasKey(Writer writer, HasKey axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomHasKey);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeClass(writer, axiom.getClasse());
        List<ObjectPropertyExpression> objList = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getObjectPropertySeq());
        boolean first = true;
        for (ObjectPropertyExpression exp : objList) {
            if (!first)
                writer.write(" ");
            first = false;
            expWriter.writeObjProp(writer, exp);
        }
        List<DataPropertyExpression> dataList = xowl.interpreter.impl.Sequences.toExpressionList(axiom.getDataPropertySeq());
        for (DataPropertyExpression exp : dataList) {
            writer.write(" ");
            first = false;
            expWriter.writeDataProp(writer, exp);
        }
        writer.write(")");
    }

    @Override protected void writeSubAnnotationPropertyOf(Writer writer, SubAnnotationPropertyOf axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomSubAnnotationPropertyOf);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeEntity(writer, axiom.getAnnotProperty());
        writer.write(" ");
        expWriter.writeEntity(writer, axiom.getSuperAnnotProperty());
        writer.write(")");
    }

    @Override protected void writeAnnotationPropertyDomain(Writer writer, AnnotationPropertyDomain axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomAnnotationPropertyDomain);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeEntity(writer, axiom.getAnnotProperty());
        writer.write(" ");
        expWriter.writeEntity(writer, axiom.getAnnotDomain());
        writer.write(")");
    }

    @Override protected void writeAnnotationPropertyRange(Writer writer, AnnotationPropertyRange axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomAnnotationPropertyRange);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeEntity(writer, axiom.getAnnotProperty());
        writer.write(" ");
        expWriter.writeEntity(writer, axiom.getAnnotRange());
        writer.write(")");
    }

    @Override protected void writeAnnotationAssertion(Writer writer, AnnotationAssertion axiom) throws IOException {
        writer.write(xowl.interpreter.frontends.VocOWL2.axiomAnnotationAssertion);
        writer.write("(");
        writeAnnotations(writer, axiom);
        expWriter.writeEntity(writer, axiom.getAnnotProperty());
        writer.write(" ");
        if (axiom.getAnnotSubject() instanceof xowl.lang.owl2.IRI)
            expWriter.writeEntity(writer, (xowl.lang.owl2.IRI)axiom.getAnnotSubject());
        else
            expWriter.writeAnonymousIndividual(writer, (xowl.lang.owl2.AnonymousIndividual)axiom.getAnnotSubject());
        writer.write(" ");
        if (axiom.getAnnotValue() instanceof xowl.lang.owl2.IRI)
            expWriter.writeEntity(writer, (xowl.lang.owl2.IRI)axiom.getAnnotValue());
        else if (axiom.getAnnotValue() instanceof xowl.lang.owl2.AnonymousIndividual)
            expWriter.writeAnonymousIndividual(writer, (xowl.lang.owl2.AnonymousIndividual)axiom.getAnnotValue());
        else
            expWriter.writeLiteral(writer, (xowl.lang.owl2.Literal)axiom.getAnnotValue());
        writer.write(")");
    }

    @Override protected void writeFunctionDefinition(Writer writer, FunctionDefinition change) throws IOException { }
}
